/**
 * The MIT License	
 * 
 * Copyright (c) 2009 Ghost Interactive
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 * ghostinteractive@gmail.com
 * http://ghostinteractive.net/blog
 * @author Jeremy brown
 */
package net.ghostinteractive.overlays
{
	import caurina.transitions.*;
	
	import flash.events.Event;
	import flash.media.*;
	import flash.net.URLRequest;
	
	public class AudioSpot
	{
		// -- Constants
		/**
		 * Fade duration for all AudioSpots, changing this value 
		 * will affect all AudioSpot instances
		 */
		public static var DEFAULT_FADE_DURATION	:Number = 5;
		
		// -- Public
		public var loop:Boolean;
		
		// -- Protected
		protected var _channel	:SoundChannel;
		protected var _sound	:Sound;
		protected var _playing	:Boolean;
		
		// -- Read Only
		protected var _audioURL	:String;
		public function get audioURL():String { return _audioURL; }
		
		protected var _gate:ProximityGate
		public function get gate():ProximityGate { return _gate; }
		
		// -- Write Only
		protected var _volume:Number;
		
		/**
		 * Constructor
		 * Listens to a ProximityGate sub-class ( RadialGate or RectangularGate ) for state
		 * change, when the gate opens the audio fades in. 
		 * When the gate closes audio fades away. If the audio has not completely 
		 * faded and the proximity gate opens, audio does not restart, it keeps playing from 
		 * it's current position.
		 * 
		 * @param _initAudioURL The url of the audio file for this instance
		 * @param _initGate		A ProximityGate or sub-class for this AudioSpot
		 */
		public function AudioSpot( _initAudioURL:String, _initGate:ProximityGate )
		{
			loop = true;
			
			_audioURL	= _initAudioURL;
			_playing	= false;
			_sound 		= new Sound();
			_sound.load( new URLRequest( _audioURL ) );
			_gate 		= _initGate;
	 
			_gate.addEventListener( Event.CLOSE, onGateClose );
			_gate.addEventListener( Event.OPEN, onGateOpen );
		}
		
		// -----------------------------------------------------
		//
		//	PUBLIC
		//	
		// -----------------------------------------------------
		
		public function destroy():void 
		{  
			if( _channel ) { 
				clearChannel()
				Tweener.removeTweens( _channel );
				_channel = null;
			}
			_gate.removeEventListener( Event.OPEN, onGateOpen );
			_gate.removeEventListener( Event.CLOSE, onGateClose );
		}
		
		public function toString():String { return 'AudioSpot: ' + _audioURL; }
		
		// -----------------------------------------------------
		//
		//	PROTECTED
		//	
		// -----------------------------------------------------		
		protected function play():void
		{
			if( !_playing ) 
			{
				clearChannel();
				_playing = true;
				_channel = _sound.play();
				_channel.soundTransform = new SoundTransform( 0 );
				_channel.addEventListener( Event.SOUND_COMPLETE, onSoundComplete );
			}
			
			tweenAudioVolume( 1, Equations.easeInSine );
		}
		
		protected function onGateOpen( event:Event ):void
		{
			play();
		}
		
		protected function onGateClose( event:Event ):void
		{
			tweenAudioVolume( 0, Equations.easeOutSine );
		}
		
		protected function tweenAudioVolume( value:Number, equation:Function ):void
		{		
			Tweener.removeTweens( _channel );
			Tweener.addTween( _channel, { _sound_volume: value, 
										  time: AudioSpot.DEFAULT_FADE_DURATION,
										  transition: equation,
										  onComplete: onAudioTweenComplete } );
		}
		
		protected function onAudioTweenComplete():void
		{
			if( _gate.state == ProximityGate.CLOSED ) {
				if( _channel ) {
					clearChannel();
					_playing = false;
				}
			}
		}
		
		protected function onSoundComplete( event:Event ):void
		{
			_playing = false;
			if( loop ) {
				play();
			} else {
				clearChannel();
			}
		}
		
		protected function clearChannel():void
		{
			if( _channel ) {
				_channel.stop();
				_channel.removeEventListener( Event.SOUND_COMPLETE, onSoundComplete );
			}
		}
	}
}